How can network data look like
Data collection vs. analyses
Visualization of bipartite networks
Linked notes are on the same level/plane
Notes are belonging to two levels/planes
Notes are belonging to multiple levels/planes
What packages are we going to use?
#library(bipartite) # mainly for network analyses
Let’s now take a look on something more common for us:
artf.net <- data.frame(a=c(10,87,35,30,10,10),b=c(5,0,0,0,0,0),c=c(7,8,0,0,1,0),d=c(30,0,0,1,0,0),e=c(1,1,0,1,3,0),f=c(0,0,0,1,0,0),g=c(0,0,1,0,0,0),h=c(0,0,1,0,1,0),i=c(0,0,0,0,0,1) )
artf.net # network
## a b c d e f g h i
## 1 10 5 7 30 1 0 0 0 0
## 2 87 0 8 0 1 0 0 0 0
## 3 35 0 0 0 0 0 1 1 0
## 4 30 0 0 1 1 1 0 0 0
## 5 10 0 1 0 3 0 0 1 0
## 6 10 0 0 0 0 0 0 0 1
plotweb(artf.net)
How we usually collect data in field:
| Time | Plot | Plant | Pollinator | Number of interactions |
|---|---|---|---|---|
| 23:30 | 1 | Cen_jac | Eri_ten | 10 |
| 23:45 | 2 | Chuq_jus | Col_ibr | 1 |
| 23:45 | 2 | Cen_jac | Eri_ten | 5 |
But we usually want something like this:
| Cen_jac | Chuq_jus | |
|---|---|---|
| Eri_ten | 15 | 0 |
| Col_ibr | 0 | 1 |
HairEye <- data.frame(HairEyeColor) # we will do a little bit of cheating here. We will use HairEyeColor and put them to the dataframe
HairEye # This is how data usually looks like when obtained in the field
## Hair Eye Sex Freq
## 1 Black Brown Male 32
## 2 Brown Brown Male 53
## 3 Red Brown Male 10
## 4 Blond Brown Male 3
## 5 Black Blue Male 11
## 6 Brown Blue Male 50
## 7 Red Blue Male 10
## 8 Blond Blue Male 30
## 9 Black Hazel Male 10
## 10 Brown Hazel Male 25
## 11 Red Hazel Male 7
## 12 Blond Hazel Male 5
## 13 Black Green Male 3
## 14 Brown Green Male 15
## 15 Red Green Male 7
## 16 Blond Green Male 8
## 17 Black Brown Female 36
## 18 Brown Brown Female 66
## 19 Red Brown Female 16
## 20 Blond Brown Female 4
## 21 Black Blue Female 9
## 22 Brown Blue Female 34
## 23 Red Blue Female 7
## 24 Blond Blue Female 64
## 25 Black Hazel Female 5
## 26 Brown Hazel Female 29
## 27 Red Hazel Female 7
## 28 Blond Hazel Female 5
## 29 Black Green Female 2
## 30 Brown Green Female 14
## 31 Red Green Female 7
## 32 Blond Green Female 8
## This is often called "long" data
## How to translate it into "wide" data?
HairEyeweb <- tapply(HairEye$Freq, list(HairEye$Hair,HairEye$Eye), sum) # simply by tapply() function
HairEyeweb
## Brown Blue Hazel Green
## Black 68 20 15 5
## Brown 119 84 54 29
## Red 26 17 14 14
## Blond 7 94 10 16
plotweb(HairEyeweb) # ploting the web
plotweb(HairEyeweb) # ploting the web
plotweb(HairEyeweb,
method="cca", # Default method is cca, which leads to as few crossings of interactions as possible. The other option is normal, which leaves order as given by the matrix.
text.rot = 90,
labsize =1,
ybig = 0.8,
low.y = 0.6,
high.y = 0.98,
plot.axes = FALSE,
y.width.low = 0.05,
y.width.high = 0.05,
low.spacing=0.01,
high.spacing=0.01,
bor.col.low = "black",
col.low = "red",
col.high = "gray",
bor.col.high = "black",
bor.col.interaction = rgb(250,250,250, alpha = 50, max=255),
col.interaction=rgb(0,0,0, alpha = 90, max=255))
visweb(HairEyeweb)
gplot(as.one.mode(HairEyeweb, project="lower"),
label=rownames(HairEyeweb), gmode="graph",
label.cex=0.6, vertex.cex=2, vertex.col="red")
Safariland
## Policana albopilosa Bombus dahlbomii
## Aristotelia chilensis 673 0
## Alstroemeria aurea 0 154
## Schinus patagonicus 0 0
## Berberis darwinii 0 67
## Rosa eglanteria 0 0
## Cynanchum diemii 0 0
## Ribes magellanicum 0 0
## Mutisia decurrens 0 0
## Calceolaria crenatiflora 0 0
## Ruizantheda mutabilis Trichophthalma amoena
## Aristotelia chilensis 110 0
## Alstroemeria aurea 0 0
## Schinus patagonicus 0 0
## Berberis darwinii 0 0
## Rosa eglanteria 6 0
## Cynanchum diemii 0 0
## Ribes magellanicum 0 2
## Mutisia decurrens 0 0
## Calceolaria crenatiflora 0 0
## Syrphus octomaculatus Manuelia gayi
## Aristotelia chilensis 0 0
## Alstroemeria aurea 5 7
## Schinus patagonicus 0 0
## Berberis darwinii 5 0
## Rosa eglanteria 4 0
## Cynanchum diemii 0 0
## Ribes magellanicum 0 0
## Mutisia decurrens 0 0
## Calceolaria crenatiflora 0 0
## Allograpta.Toxomerus Trichophthalma jaffueli Phthiria
## Aristotelia chilensis 0 0 0
## Alstroemeria aurea 1 3 8
## Schinus patagonicus 0 0 0
## Berberis darwinii 0 0 0
## Rosa eglanteria 2 0 0
## Cynanchum diemii 0 0 0
## Ribes magellanicum 3 0 0
## Mutisia decurrens 0 0 1
## Calceolaria crenatiflora 1 0 0
## Platycheirus1 Sapromyza.Minettia Formicidae3
## Aristotelia chilensis 4 0 0
## Alstroemeria aurea 1 1 0
## Schinus patagonicus 0 0 0
## Berberis darwinii 0 0 0
## Rosa eglanteria 0 0 0
## Cynanchum diemii 0 0 8
## Ribes magellanicum 0 0 0
## Mutisia decurrens 0 0 0
## Calceolaria crenatiflora 0 0 0
## Nitidulidae Staphilinidae Ichneumonidae4 Braconidae3
## Aristotelia chilensis 0 0 1 0
## Alstroemeria aurea 0 4 0 0
## Schinus patagonicus 0 0 15 0
## Berberis darwinii 0 0 0 0
## Rosa eglanteria 0 3 0 0
## Cynanchum diemii 1 0 0 2
## Ribes magellanicum 0 0 0 0
## Mutisia decurrens 0 0 0 0
## Calceolaria crenatiflora 0 0 0 0
## Chalepogenus caeruleus Vespula germanica Torymidae2
## Aristotelia chilensis 0 0 0
## Alstroemeria aurea 0 4 0
## Schinus patagonicus 0 0 0
## Berberis darwinii 0 0 0
## Rosa eglanteria 0 0 0
## Cynanchum diemii 0 0 9
## Ribes magellanicum 0 0 0
## Mutisia decurrens 0 0 0
## Calceolaria crenatiflora 3 0 0
## Phthiria1 Svastrides melanura Sphecidae Thomisidae
## Aristotelia chilensis 0 0 0 0
## Alstroemeria aurea 1 6 1 1
## Schinus patagonicus 0 0 0 0
## Berberis darwinii 0 0 0 0
## Rosa eglanteria 0 0 0 0
## Cynanchum diemii 0 0 0 0
## Ribes magellanicum 0 0 0 0
## Mutisia decurrens 0 0 0 0
## Calceolaria crenatiflora 0 0 0 0
## Corynura prothysteres Ichneumonidae2
## Aristotelia chilensis 1 0
## Alstroemeria aurea 3 4
## Schinus patagonicus 0 0
## Berberis darwinii 0 0
## Rosa eglanteria 0 0
## Cynanchum diemii 0 0
## Ribes magellanicum 0 0
## Mutisia decurrens 0 0
## Calceolaria crenatiflora 0 0
## Ruizantheda proxima Braconidae2
## Aristotelia chilensis 0 1
## Alstroemeria aurea 4 0
## Schinus patagonicus 0 0
## Berberis darwinii 0 0
## Rosa eglanteria 0 0
## Cynanchum diemii 0 0
## Ribes magellanicum 0 0
## Mutisia decurrens 0 0
## Calceolaria crenatiflora 0 0
Safariland
## Policana albopilosa Bombus dahlbomii
## Aristotelia chilensis 673 0
## Alstroemeria aurea 0 154
## Schinus patagonicus 0 0
## Berberis darwinii 0 67
## Rosa eglanteria 0 0
## Cynanchum diemii 0 0
## Ribes magellanicum 0 0
## Mutisia decurrens 0 0
## Calceolaria crenatiflora 0 0
## Ruizantheda mutabilis Trichophthalma amoena
## Aristotelia chilensis 110 0
## Alstroemeria aurea 0 0
## Schinus patagonicus 0 0
## Berberis darwinii 0 0
## Rosa eglanteria 6 0
## Cynanchum diemii 0 0
## Ribes magellanicum 0 2
## Mutisia decurrens 0 0
## Calceolaria crenatiflora 0 0
## Syrphus octomaculatus Manuelia gayi
## Aristotelia chilensis 0 0
## Alstroemeria aurea 5 7
## Schinus patagonicus 0 0
## Berberis darwinii 5 0
## Rosa eglanteria 4 0
## Cynanchum diemii 0 0
## Ribes magellanicum 0 0
## Mutisia decurrens 0 0
## Calceolaria crenatiflora 0 0
## Allograpta.Toxomerus Trichophthalma jaffueli Phthiria
## Aristotelia chilensis 0 0 0
## Alstroemeria aurea 1 3 8
## Schinus patagonicus 0 0 0
## Berberis darwinii 0 0 0
## Rosa eglanteria 2 0 0
## Cynanchum diemii 0 0 0
## Ribes magellanicum 3 0 0
## Mutisia decurrens 0 0 1
## Calceolaria crenatiflora 1 0 0
## Platycheirus1 Sapromyza.Minettia Formicidae3
## Aristotelia chilensis 4 0 0
## Alstroemeria aurea 1 1 0
## Schinus patagonicus 0 0 0
## Berberis darwinii 0 0 0
## Rosa eglanteria 0 0 0
## Cynanchum diemii 0 0 8
## Ribes magellanicum 0 0 0
## Mutisia decurrens 0 0 0
## Calceolaria crenatiflora 0 0 0
## Nitidulidae Staphilinidae Ichneumonidae4 Braconidae3
## Aristotelia chilensis 0 0 1 0
## Alstroemeria aurea 0 4 0 0
## Schinus patagonicus 0 0 15 0
## Berberis darwinii 0 0 0 0
## Rosa eglanteria 0 3 0 0
## Cynanchum diemii 1 0 0 2
## Ribes magellanicum 0 0 0 0
## Mutisia decurrens 0 0 0 0
## Calceolaria crenatiflora 0 0 0 0
## Chalepogenus caeruleus Vespula germanica Torymidae2
## Aristotelia chilensis 0 0 0
## Alstroemeria aurea 0 4 0
## Schinus patagonicus 0 0 0
## Berberis darwinii 0 0 0
## Rosa eglanteria 0 0 0
## Cynanchum diemii 0 0 9
## Ribes magellanicum 0 0 0
## Mutisia decurrens 0 0 0
## Calceolaria crenatiflora 3 0 0
## Phthiria1 Svastrides melanura Sphecidae Thomisidae
## Aristotelia chilensis 0 0 0 0
## Alstroemeria aurea 1 6 1 1
## Schinus patagonicus 0 0 0 0
## Berberis darwinii 0 0 0 0
## Rosa eglanteria 0 0 0 0
## Cynanchum diemii 0 0 0 0
## Ribes magellanicum 0 0 0 0
## Mutisia decurrens 0 0 0 0
## Calceolaria crenatiflora 0 0 0 0
## Corynura prothysteres Ichneumonidae2
## Aristotelia chilensis 1 0
## Alstroemeria aurea 3 4
## Schinus patagonicus 0 0
## Berberis darwinii 0 0
## Rosa eglanteria 0 0
## Cynanchum diemii 0 0
## Ribes magellanicum 0 0
## Mutisia decurrens 0 0
## Calceolaria crenatiflora 0 0
## Ruizantheda proxima Braconidae2
## Aristotelia chilensis 0 1
## Alstroemeria aurea 4 0
## Schinus patagonicus 0 0
## Berberis darwinii 0 0
## Rosa eglanteria 0 0
## Cynanchum diemii 0 0
## Ribes magellanicum 0 0
## Mutisia decurrens 0 0
## Calceolaria crenatiflora 0 0
plotweb(Safariland, method = "cca")
visweb(Safariland)
jc_net <- read.csv("jc_network21.csv")
head(jc_net)
## pollinator day hour min plot plant number sex shade note is.pollinator
## 1 Aglais_urticae 14 16 50 39 Bet_off 1 <NA> 0 <NA> T
## 2 Aglais_urticae 14 9 28 36 Cen_jac 1 <NA> 0 <NA> T
## 3 Aglais_urticae 14 15 58 9 Suc_pra 1 <NA> 0 <NA> T
## 4 Aglais_urticae 14 13 39 41 Tri_pra 1 <NA> 0 <NA> T
## 5 Aglais_urticae 15 13 34 9 Suc_pra 1 <NA> 0 <NA> T
## 6 Aglais_urticae 14 17 37 9 Suc_pra 1 <NA> 0 <NA> T
jc_net <- read.csv("jc_network21.csv")
head(jc_net)
## pollinator day hour min plot plant number sex shade note is.pollinator
## 1 Aglais_urticae 14 16 50 39 Bet_off 1 <NA> 0 <NA> T
## 2 Aglais_urticae 14 9 28 36 Cen_jac 1 <NA> 0 <NA> T
## 3 Aglais_urticae 14 15 58 9 Suc_pra 1 <NA> 0 <NA> T
## 4 Aglais_urticae 14 13 39 41 Tri_pra 1 <NA> 0 <NA> T
## 5 Aglais_urticae 15 13 34 9 Suc_pra 1 <NA> 0 <NA> T
## 6 Aglais_urticae 14 17 37 9 Suc_pra 1 <NA> 0 <NA> T
jc_web <- tapply(jc_net$number , list(jc_net$pollinator, jc_net$plant), sum) #
jc_web[is.na(jc_web)] <- 0 # replace NA with 0
plotweb(jc_web, "cca")
plotweb(jc_web, "cca", col.interaction = rgb(0,0,0, max = 255, alpha = 100), bor.col.interaction = rgb(0,0,0, max = 255, alpha = 100))
library(networkD3)
## Warning: package 'networkD3' was built under R version 4.2.3
# Load energy projection data
URL <- "https://cdn.rawgit.com/christophergandrud/networkD3/master/JSONdata/energy.json"
Energy <- jsonlite::fromJSON(URL)
# Now we have 2 data frames: a 'links' data frame with 3 columns (from, to, value), and a 'nodes' data frame that gives the name of each node.
head( Energy$links )
## source target value
## 1 0 1 124.729
## 2 1 2 0.597
## 3 1 3 26.862
## 4 1 4 280.322
## 5 1 5 81.144
## 6 6 2 35.000
head( Energy$nodes )
## name
## 1 Agricultural 'waste'
## 2 Bio-conversion
## 3 Liquid
## 4 Losses
## 5 Solid
## 6 Gas
# Thus we can plot it
p <- sankeyNetwork(Links = Energy$links, Nodes = Energy$nodes, Source = "source",
Target = "target", Value = "value", NodeID = "name",
units = "TWh", fontSize = 12, nodeWidth = 30)
p
# save the widget
# library(htmlwidgets)
# saveWidget(p, file=paste0( getwd(), "/HtmlWidget/sankeyEnergy.html"))
library(networkD3)
library(tidyverse)
## Warning: package 'tidyverse' was built under R version 4.2.3
## Warning: package 'ggplot2' was built under R version 4.2.3
## Warning: package 'tibble' was built under R version 4.2.3
## Warning: package 'tidyr' was built under R version 4.2.3
## Warning: package 'readr' was built under R version 4.2.3
## Warning: package 'purrr' was built under R version 4.2.3
## Warning: package 'dplyr' was built under R version 4.2.3
## Warning: package 'forcats' was built under R version 4.2.3
## Warning: package 'lubridate' was built under R version 4.2.3
## ── Attaching core tidyverse packages ──────────────────────── tidyverse 2.0.0 ──
## ✔ dplyr 1.1.2 ✔ readr 2.1.4
## ✔ forcats 1.0.0 ✔ stringr 1.5.0
## ✔ ggplot2 3.4.3 ✔ tibble 3.2.1
## ✔ lubridate 1.9.3 ✔ tidyr 1.3.0
## ✔ purrr 1.0.2
## ── Conflicts ────────────────────────────────────────── tidyverse_conflicts() ──
## ✖ lubridate::%--%() masks igraph::%--%()
## ✖ dplyr::as_data_frame() masks tibble::as_data_frame(), igraph::as_data_frame()
## ✖ purrr::compose() masks igraph::compose()
## ✖ tidyr::crossing() masks igraph::crossing()
## ✖ dplyr::filter() masks stats::filter()
## ✖ dplyr::lag() masks stats::lag()
## ✖ purrr::simplify() masks igraph::simplify()
## ℹ Use the conflicted package (<http://conflicted.r-lib.org/>) to force all conflicts to become errors
data
## function (..., list = character(), package = NULL, lib.loc = NULL,
## verbose = getOption("verbose"), envir = .GlobalEnv, overwrite = TRUE)
## {
## fileExt <- function(x) {
## db <- grepl("\\.[^.]+\\.(gz|bz2|xz)$", x)
## ans <- sub(".*\\.", "", x)
## ans[db] <- sub(".*\\.([^.]+\\.)(gz|bz2|xz)$", "\\1\\2",
## x[db])
## ans
## }
## my_read_table <- function(...) {
## lcc <- Sys.getlocale("LC_COLLATE")
## on.exit(Sys.setlocale("LC_COLLATE", lcc))
## Sys.setlocale("LC_COLLATE", "C")
## read.table(...)
## }
## stopifnot(is.character(list))
## names <- c(as.character(substitute(list(...))[-1L]), list)
## if (!is.null(package)) {
## if (!is.character(package))
## stop("'package' must be a character vector or NULL")
## }
## paths <- find.package(package, lib.loc, verbose = verbose)
## if (is.null(lib.loc))
## paths <- c(path.package(package, TRUE), if (!length(package)) getwd(),
## paths)
## paths <- unique(normalizePath(paths[file.exists(paths)]))
## paths <- paths[dir.exists(file.path(paths, "data"))]
## dataExts <- tools:::.make_file_exts("data")
## if (length(names) == 0L) {
## db <- matrix(character(), nrow = 0L, ncol = 4L)
## for (path in paths) {
## entries <- NULL
## packageName <- if (file_test("-f", file.path(path,
## "DESCRIPTION")))
## basename(path)
## else "."
## if (file_test("-f", INDEX <- file.path(path, "Meta",
## "data.rds"))) {
## entries <- readRDS(INDEX)
## }
## else {
## dataDir <- file.path(path, "data")
## entries <- tools::list_files_with_type(dataDir,
## "data")
## if (length(entries)) {
## entries <- unique(tools::file_path_sans_ext(basename(entries)))
## entries <- cbind(entries, "")
## }
## }
## if (NROW(entries)) {
## if (is.matrix(entries) && ncol(entries) == 2L)
## db <- rbind(db, cbind(packageName, dirname(path),
## entries))
## else warning(gettextf("data index for package %s is invalid and will be ignored",
## sQuote(packageName)), domain = NA, call. = FALSE)
## }
## }
## colnames(db) <- c("Package", "LibPath", "Item", "Title")
## footer <- if (missing(package))
## paste0("Use ", sQuote(paste("data(package =", ".packages(all.available = TRUE))")),
## "\n", "to list the data sets in all *available* packages.")
## else NULL
## y <- list(title = "Data sets", header = NULL, results = db,
## footer = footer)
## class(y) <- "packageIQR"
## return(y)
## }
## paths <- file.path(paths, "data")
## for (name in names) {
## found <- FALSE
## for (p in paths) {
## tmp_env <- if (overwrite)
## envir
## else new.env()
## if (file_test("-f", file.path(p, "Rdata.rds"))) {
## rds <- readRDS(file.path(p, "Rdata.rds"))
## if (name %in% names(rds)) {
## found <- TRUE
## if (verbose)
## message(sprintf("name=%s:\t found in Rdata.rds",
## name), domain = NA)
## thispkg <- sub(".*/([^/]*)/data$", "\\1", p)
## thispkg <- sub("_.*$", "", thispkg)
## thispkg <- paste0("package:", thispkg)
## objs <- rds[[name]]
## lazyLoad(file.path(p, "Rdata"), envir = tmp_env,
## filter = function(x) x %in% objs)
## break
## }
## else if (verbose)
## message(sprintf("name=%s:\t NOT found in names() of Rdata.rds, i.e.,\n\t%s\n",
## name, paste(names(rds), collapse = ",")),
## domain = NA)
## }
## if (file_test("-f", file.path(p, "Rdata.zip"))) {
## warning("zipped data found for package ", sQuote(basename(dirname(p))),
## ".\nThat is defunct, so please re-install the package.",
## domain = NA)
## if (file_test("-f", fp <- file.path(p, "filelist")))
## files <- file.path(p, scan(fp, what = "", quiet = TRUE))
## else {
## warning(gettextf("file 'filelist' is missing for directory %s",
## sQuote(p)), domain = NA)
## next
## }
## }
## else {
## files <- list.files(p, full.names = TRUE)
## }
## files <- files[grep(name, files, fixed = TRUE)]
## if (length(files) > 1L) {
## o <- match(fileExt(files), dataExts, nomatch = 100L)
## paths0 <- dirname(files)
## paths0 <- factor(paths0, levels = unique(paths0))
## files <- files[order(paths0, o)]
## }
## if (length(files)) {
## for (file in files) {
## if (verbose)
## message("name=", name, ":\t file= ...", .Platform$file.sep,
## basename(file), "::\t", appendLF = FALSE,
## domain = NA)
## ext <- fileExt(file)
## if (basename(file) != paste0(name, ".", ext))
## found <- FALSE
## else {
## found <- TRUE
## zfile <- file
## zipname <- file.path(dirname(file), "Rdata.zip")
## if (file.exists(zipname)) {
## Rdatadir <- tempfile("Rdata")
## dir.create(Rdatadir, showWarnings = FALSE)
## topic <- basename(file)
## rc <- .External(C_unzip, zipname, topic,
## Rdatadir, FALSE, TRUE, FALSE, FALSE)
## if (rc == 0L)
## zfile <- file.path(Rdatadir, topic)
## }
## if (zfile != file)
## on.exit(unlink(zfile))
## switch(ext, R = , r = {
## library("utils")
## sys.source(zfile, chdir = TRUE, envir = tmp_env)
## }, RData = , rdata = , rda = load(zfile,
## envir = tmp_env), TXT = , txt = , tab = ,
## tab.gz = , tab.bz2 = , tab.xz = , txt.gz = ,
## txt.bz2 = , txt.xz = assign(name, my_read_table(zfile,
## header = TRUE, as.is = FALSE), envir = tmp_env),
## CSV = , csv = , csv.gz = , csv.bz2 = ,
## csv.xz = assign(name, my_read_table(zfile,
## header = TRUE, sep = ";", as.is = FALSE),
## envir = tmp_env), found <- FALSE)
## }
## if (found)
## break
## }
## if (verbose)
## message(if (!found)
## "*NOT* ", "found", domain = NA)
## }
## if (found)
## break
## }
## if (!found) {
## warning(gettextf("data set %s not found", sQuote(name)),
## domain = NA)
## }
## else if (!overwrite) {
## for (o in ls(envir = tmp_env, all.names = TRUE)) {
## if (exists(o, envir = envir, inherits = FALSE))
## warning(gettextf("an object named %s already exists and will not be overwritten",
## sQuote(o)))
## else assign(o, get(o, envir = tmp_env, inherits = FALSE),
## envir = envir)
## }
## rm(tmp_env)
## }
## }
## invisible(names)
## }
## <bytecode: 0x0000025bdc6464d0>
## <environment: namespace:utils>
# I need a long format
data_long <- data.frame(jc_web) %>%
rownames_to_column %>%
gather(key = 'key', value = 'value', -rowname) %>%
filter(value > 0)
colnames(data_long) <- c("source", "target", "value")
data_long$target <- paste(data_long$target, " ", sep="")
# From these flows we need to create a node data frame: it lists every entities involved in the flow
nodes <- data.frame(name=c(as.character(data_long$source), as.character(data_long$target)) %>% unique())
# With networkD3, connection must be provided using id, not using real name like in the links dataframe.. So we need to reformat it.
data_long$IDsource=match(data_long$source, nodes$name)-1
data_long$IDtarget=match(data_long$target, nodes$name)-1
# prepare colour scale
# Make the Network
sankeyNetwork(Links = data_long, Nodes = nodes,
Source = "IDsource", Target = "IDtarget",
Value = "value", NodeID = "name",
sinksRight=FALSE, nodeWidth=40, fontSize=13, nodePadding=20)
Network of US airports and domestic flights